#include "Generate_C_std.h"


class Pattern_class_def : public Pattern
{
public:
	bool match(Statement* that)
	{
		use_scope = false;
		pattern = new Wildcard<Class_def>;
		return that->match(pattern);
	}

	void generate_code(Generate_C* gen)
	{
		// Compile the class members
		foreach (Member* member, *pattern->value->members)
		{
			Method* method = dynamic_cast<Method*>(member);

			if(method != NULL)
			{
				buf << gen->compile_statement(method);
			} 
		}

		// Declare all class members
		function_declaration_block(buf, pattern->value->attrs->get_list<Signature>("phc.codegen.compiled_functions"), pattern->value->class_name->value);

		// Create the class entry in MINIT
		minit
		<< "{\n"
		<< "zend_class_entry ce; // temp\n"
		<< "zend_class_entry* ce_reg; // once registered, ce_ptr should be used\n"
		<< "INIT_CLASS_ENTRY(ce, " 
		<< "\"" << *pattern->value->class_name->value << "\", " 
		<< *pattern->value->class_name->value << "_functions);\n"
		;

		// Register the class
		CLASS_NAME* parent = pattern->value->extends;
		if(parent != NULL)
		{
			minit 
			<< "zend_class_entry* parent;\n"
			<< "parent = zend_fetch_class(\"" << *parent->value << "\", " << parent->value->length() << ", ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC);\n"
			<< "ce_reg = zend_register_internal_class_ex(&ce, parent, \"" << *parent->value << "\" TSRMLS_CC);\n";
			;
		}
		else
		{
			minit << "ce_reg = zend_register_internal_class(&ce TSRMLS_CC);\n";
		}

		// Clear the ZEND_INTERNAL_CLASS flag so that we can add complex zvals
		// as class attributes. TODO: not sure what the consequences of this are.
		minit << "ce_reg->type &= ~ZEND_INTERNAL_CLASS;\n";

		// Compile attributes
		foreach (Member* member, *pattern->value->members)
		{
			Attribute* attr = dynamic_cast<Attribute*>(member);

			if(attr != NULL)
			{
				minit << "{\n";
				
				// We must have a default value
				assert(attr->var->default_value != NULL);
				gen->compile_static_value("default_value", minit, attr->var->default_value);

				if(!attr->attr_mod->is_const)
				{
					minit 
					<< "phc_declare_property(ce_reg, "
					<< "\"" << *attr->var->variable_name->value << "\", " 
					<< attr->var->variable_name->value->size() << ", "
					<< "default_value, "
					<< attr_mod_flags(attr->attr_mod) << " " 
					<< "TSRMLS_CC);"
					;
				}
				else if(attr->attr_mod->is_const)
				{
					// TODO: implement
					// (Const attributes must be added using a different API)
					phc_unsupported (attr, "const attribute");
				}

				minit << "}";
			}
		}

		minit << "}";
	}

protected:
	Wildcard<Class_def>* pattern;
};

CREATE(Generate_C_classdef)
